package util.clock;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.Vector;

public class VectorClock {
	private Vector<Integer> vector = null; 
	private static VectorClock instance = null;
	private static Properties prop = null;
	private final static int otherInitValue = -1;
	private final static int myInitValue = 1;
	
	static {
		prop = new Properties();
		try {
			prop.load(new FileInputStream("vector.properties"));
		} catch (FileNotFoundException e) {

			prop.setProperty("nProc", "1");
			prop.setProperty("myId", "100");
			
			try {
				prop.store(new FileWriter(new File("conf.properties")), "configuration faile");
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 *
	 * @param key
	 * @return
	 */
	public static String getString(String key) {
		try {
			return prop.getProperty(key).toString();
		} catch (MissingResourceException e) {
			return '!' + key + '!';
		}
	}
	
	/**
	 * Numero massimo di processi
	 */
	public final static int nProc = Integer.parseInt(VectorClock.getString("chunkSize"));
	/**
	 * id del Processo
	 */
	public final static int myId = Integer.parseInt(VectorClock.getString("myId"));
	
	
	/**
	 * Costruttore di default del singleton
	 * @param nProc
	 * @param myId
	 */
	private  VectorClock() {
		vector = new Vector<Integer>(VectorClock.nProc);
		for (int index = 0; index < nProc; index ++)
			vector.add(index, otherInitValue);
		
		vector.add(myId, myInitValue);
	}
	
	/**
	 * 
	 * @return
	 */
	public static int tick() {
		return VectorClock.getInstance().vector.get(myId) + 1;
	}
	
	/**
	 * 
	 * @return
	 */
	public Collection<Integer> send() {
		VectorClock.getInstance().vector.add(VectorClock.getInstance().vector.get(myId) + 1, myId);
		return VectorClock.getInstance().vector;
	}
	
	/**
	 * 
	 * @param values
	 * @return
	 */
	public int receive(Integer[] values) {
		
		for (int index = 0; index < nProc; index ++) {
			if (index == myId) // incremento il mio
				VectorClock.getInstance().vector.add(myId, VectorClock.getInstance().vector.get(myId) + 1);
			else //Aggiorno quello dei vicini
				VectorClock.getInstance().vector.add(index, 
						values[index] > VectorClock.getInstance().vector.get(index) ?  
								values[index] : VectorClock.getInstance().vector.get(index));
		}
		
		return -1;
	}
	
	public static VectorClock getInstance() {
		if (instance == null) {
			synchronized (VectorClock.class) {
				if (instance == null) {
					instance = new VectorClock();
				}
			}
		}
		return (instance);		
	}
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder(this.getClass().getSimpleName());
		sb.append(" ").append("myId: ").append(myId)
			.append("\n\tvector: ");
		for (int index = 0; index < nProc; index ++) 
			sb.append("\n\t\t").append("id: ").append(index).append(" value:").append(vector.get(index));
		
		return sb.toString();
	}
}
